package com.google.code.jholidays.events.parameters;

import java.util.Calendar;
import java.util.Date;

/**
 * Stores day in month index and month index itself.
 * 
 * @author tillias
 * 
 */
public class DayMonthPair {

    /**
     * Creates new day-month pair. Validates if both day and month may form
     * valid {@link Date} object
     * 
     * @param date
     *            Day of month. Count starts from 1
     * @param month
     *            Month. Count starts from 1
     * @throws IllegalArgumentException
     *             Thrown if invalid day/month is specified (e.g. they can't
     *             form valid {@link Date} object
     */
    public DayMonthPair(int date, int month) throws IllegalArgumentException {

	verifyMonth(month);

	verifyDayOfMonth(date, month);

	this.date = date;
	this.month = month;
    }

    /**
     * Gets day of month
     * 
     * @return Day of month. Count starts from 1
     */
    public int getDay() {
	return date;
    }

    /**
     * Gets month
     * 
     * @return Month. Count starts from 1
     */
    public int getMonth() {
	return month;
    }

    /**
     * Gets date using day and month stored inside this pair
     * 
     * @param year
     *            Year which will be used to construct date
     * @return Date instance
     */
    public Date getDate(int year) {
	Calendar calendar = Calendar.getInstance();
	calendar.clear();
	calendar.set(year, getMonth() - 1, getDay());

	return calendar.getTime();
    }

    private void verifyMonth(int v_month) throws IllegalArgumentException {
	if (v_month < Calendar.JANUARY + 1 || v_month > Calendar.DECEMBER + 1)
	    throw new IllegalArgumentException("Invalid month. "
		    + Integer.toString(v_month));
    }

    private void verifyDayOfMonth(int v_day, int v_month)
	    throws IllegalArgumentException {

	boolean failed = false;

	// special check for February
	if (v_month == Calendar.FEBRUARY + 1) {
	    if (v_day < 1 || v_day > 29)
		failed = true;
	} else {
	    // verify day
	    Calendar c = Calendar.getInstance();
	    c.set(Calendar.MONTH, v_month - 1);
	    c.set(Calendar.DATE, 1); // first day of month
	    int maxDay = c.getActualMaximum(Calendar.DATE);
	    int minDay = c.getActualMinimum(Calendar.DATE);

	    if (v_day < minDay || v_day > maxDay)
		failed = true;
	}

	if (failed)
	    throw new IllegalArgumentException("Invalid day. "
		    + Integer.toString(v_day));
    }

    int date;
    int month;
}
